home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 9 / Night Owl CD-ROM (NOPV9) (Night Owl Publisher) (1993).ISO / 009a / tde221.zip / UTILS.C < prev    next >
C/C++ Source or Header  |  1993-04-01  |  77KB  |  2,772 lines

  1. /*******************  start of original comments  ********************/
  2. /*
  3.  * Written by Douglas Thomson (1989/1990)
  4.  *
  5.  * This source code is released into the public domain.
  6.  */
  7.  
  8. /*
  9.  * Name:    dte - Doug's Text Editor program - miscellaneous utilities
  10.  * Purpose: This file contains miscellaneous functions that were required
  11.  *           in more than one of the other files, or were thought to be
  12.  *           likely to be used elsewhere in the future.
  13.  * File:    utils.c
  14.  * Author:  Douglas Thomson
  15.  * System:  this file is intended to be system-independent
  16.  * Date:    October 1, 1989
  17.  */
  18. /*********************  end of original comments  ********************/
  19.  
  20.  
  21. /*
  22.  * The utility routines have been EXTENSIVELY rewritten.  Update screens as
  23.  * needed.  Most times, only one line has changed.  Just show changed line
  24.  * in all windows if it is on screen.
  25.  *
  26.  * Support routines for text lines longer than screen width have been added.
  27.  * Currently support lines as long as 1040 characters.
  28.  *
  29.  * In DTE, Doug chose to test whether characters are part of a word.  In TDE,
  30.  * we will test whether characters are not part of a word.  The character
  31.  * set not part of a word will not change as much as the characters that
  32.  * are part of a word.  In most languages, human and computer, the delimiters
  33.  * are much more common across languages than the tokens that make up a word.
  34.  * Thanks to Pierre Jelenc, pcj1@columbia.edu, for recommending looking for
  35.  * delimiters.
  36.  *
  37.  * New editor name:  TDE, the Thomson-Davis Editor.
  38.  * Author:           Frank Davis
  39.  * Date:             June 5, 1991, version 1.0
  40.  * Date:             July 29, 1991, version 1.1
  41.  * Date:             October 5, 1991, version 1.2
  42.  * Date:             January 20, 1992, version 1.3
  43.  * Date:             February 17, 1992, version 1.4
  44.  * Date:             April 1, 1992, version 1.5
  45.  * Date:             June 5, 1992, version 2.0
  46.  * Date:             October 31, 1992, version 2.1
  47.  * Date:             April 1, 1993, version 2.2
  48.  *
  49.  * This modification of Douglas Thomson's code is released into the
  50.  * public domain, Frank Davis.  You may distribute it freely.
  51.  */
  52.  
  53. #include "tdestr.h"
  54. #include "common.h"
  55. #include "define.h"
  56. #include "tdefunc.h"
  57.  
  58.  
  59. /*
  60.  * Name:    myiswhitespc
  61.  * Purpose: To determine whether or not a character is *NOT* part of a "word".
  62.  * Date:    July 4, 1992
  63.  * Passed:  c: the character to be tested
  64.  * Returns: TRUE if c is in the character set *NOT* part of a word
  65.  * Notes:   The characters in the set not part of a word will not change as
  66.  *           as much as the characters that are part of a word.  In most
  67.  *           languages, human and computer, the delimiters are much more
  68.  *           common than the tokens that make up a word.  For example,
  69.  *           the set of punction characters don't change as much across
  70.  *           languages, human and computer, as the characters that make
  71.  *           up the alphabet, usually.  In other words, the delimiters
  72.  *           are fairly constant across languages.
  73.  */
  74. int  myiswhitespc( int c )
  75. {
  76.    return( c == ' ' || (ispunct( c ) && c != '_') || iscntrl( c ) );
  77. }
  78.  
  79.  
  80. /*
  81.  * Name:    check_virtual_col
  82.  * Purpose: ensure integrity of rcol, ccol, and bcol
  83.  * Date:    June 5, 1991
  84.  * Passed:  window:  pointer to current window
  85.  *          rcol: real column of cursor
  86.  *          ccol: current or logical column of cursor
  87.  */
  88. void check_virtual_col( WINDOW *window, int rcol, int ccol )
  89. {
  90. register int bcol;
  91. int  start_col;
  92. int  end_col;
  93. file_infos *file;
  94.  
  95.    file      = window->file_info;
  96.    bcol      = window->bcol;
  97.    start_col = window->start_col;
  98.    end_col   = window->end_col;
  99.  
  100.    /*
  101.     * is logical column past end of screen?
  102.     */
  103.    if (ccol > end_col) {
  104. /*      ccol = start_col + (end_col + 1 - start_col) / 2;  */
  105.       ccol = end_col;
  106.       bcol = rcol - (ccol - start_col);
  107.       file->dirty = LOCAL;
  108.    }
  109.  
  110.    /*
  111.     * is logical column behind start of screen?
  112.     */
  113.    if (ccol < start_col) {
  114.       if (bcol >= (start_col - ccol))
  115.          bcol -= (start_col - ccol);
  116.       ccol = start_col;
  117.       file->dirty = LOCAL;
  118.    }
  119.  
  120.    /*
  121.     * is real column < base column?
  122.     */
  123.    if (rcol < bcol) {
  124.       ccol = rcol + start_col;
  125.       bcol = 0;
  126.       if (ccol > end_col) {
  127.          bcol = rcol;
  128.          ccol = start_col;
  129.       }
  130.       file->dirty = LOCAL;
  131.    }
  132.  
  133.    /*
  134.     * current column + base column MUST equal real column
  135.     */
  136.    if ((ccol - start_col) + bcol != rcol) {
  137.       if (bcol < 0 || bcol > rcol) {
  138.          bcol = rcol;
  139.          file->dirty = LOCAL;
  140.       }
  141.       ccol = rcol - bcol + start_col;
  142.       if (ccol > end_col) {
  143.          bcol = rcol;
  144.          ccol = start_col;
  145.          file->dirty = LOCAL;
  146.       }
  147.    }
  148.  
  149.    /*
  150.     * rcol CANNOT be negative
  151.     */
  152.    if (rcol < 0) {
  153.       rcol = bcol = 0;
  154.       ccol = start_col;
  155.       file->dirty = LOCAL;
  156.    }
  157.  
  158.    if (rcol >= MAX_LINE_LENGTH) {
  159.       rcol = MAX_LINE_LENGTH - 1;
  160.       bcol = rcol - (ccol - start_col);
  161.    }
  162.  
  163.    assert( rcol >= 0 );
  164.    assert( rcol < MAX_LINE_LENGTH );
  165.    assert( bcol >= 0 );
  166.    assert( bcol < MAX_LINE_LENGTH );
  167.    assert( ccol >= start_col );
  168.    assert( ccol <= end_col );
  169.  
  170.    window->bcol = bcol;
  171.    window->ccol = ccol;
  172.    window->rcol = rcol;
  173. }
  174.  
  175.  
  176. /*
  177.  * Name:    copy_line
  178.  * Purpose: To copy the cursor line, if necessary, into the current line
  179.  *           buffer, so that changes can be made efficiently.
  180.  * Date:    June 5, 1991
  181.  * Passed:  text_line: line to be copied to line buffer
  182.  *          line: line to display error message
  183.  * Notes:   See un_copy_line, the reverse operation.
  184.  *          DO NOT use the C library string functions on text in
  185.  *           g_status.line_buff, because Null characters are allowed as
  186.  *           normal text in the file.
  187.  */
  188. void copy_line( line_list_ptr ll )
  189. {
  190. register unsigned int len;
  191. text_ptr text_line;
  192.  
  193.    if (g_status.copied == FALSE  &&  ll->len != EOF) {
  194.  
  195.       assert( ll != NULL );
  196.  
  197.       len = ll->len;
  198.       text_line = ll->line;
  199.       g_status.buff_node = ll;
  200.  
  201.       assert( len < MAX_LINE_LENGTH );
  202.  
  203.       if (text_line != NULL)
  204.          _fmemcpy( g_status.line_buff, text_line, len );
  205.  
  206.       g_status.line_buff_len = len;
  207.       g_status.copied = TRUE;
  208.    }
  209. }
  210.  
  211.  
  212. /*
  213.  * Name:    un_copy_line
  214.  * Purpose: To copy the cursor line, if necessary, from the current line
  215.  *           buffer, shifting the main text to make the right amount of
  216.  *           room.
  217.  * Date:    June 5, 1991
  218.  * Passed:  test_line:  location in file to copy line buffer
  219.  *          window:  pointer to current window
  220.  *          del_trailing:  delete the trailing blanks at eol? TRUE or FALSE
  221.  * Notes:   For some functions, trailing spaces should not be removed when
  222.  *           returning the line buffer to the main text.  The JoinLine function
  223.  *           is a good example.  We need to leave trailing space so when we
  224.  *           join lines - the current line will extend at least up to
  225.  *           the column of the cursor.  We need to leave trailing space
  226.  *           during BOX block operations.
  227.  *          See copy_line, the reverse operation.
  228.  */
  229. int  un_copy_line( line_list_ptr ll, WINDOW *window, int del_trailing )
  230. {
  231. text_ptr p;
  232. size_t len;     /* length of line buffer text */
  233. size_t ll_len;  /* length of ll->line */
  234. int  net_change;
  235. int  rc;
  236. char c;
  237. file_infos *file;
  238. WINDOW *wp;
  239.  
  240.    rc = OK;
  241.    if (mode.do_backups == TRUE)
  242.       rc = backup_file( window );
  243.  
  244.    if (g_status.copied == TRUE  &&  ll->len != EOF) {
  245.  
  246.       file = window->file_info;
  247.  
  248.       /*
  249.        * if we are deleting the entire line, don't worry about the
  250.        *  deleting the trailing space, since we're deleting entire line.
  251.        */
  252.       if (g_status.command == DeleteLine)
  253.          del_trailing = FALSE;
  254.  
  255.       if (del_trailing  &&  mode.trailing  &&  file->crlf != BINARY) {
  256.          len = g_status.line_buff_len;
  257.          for (p=(text_ptr)(g_status.line_buff+len); len > 0; len--, p--) {
  258.             c = *(p - 1);
  259.             if (c != ' '  &&  c != '\t')
  260.                break;
  261.             if (!mode.inflate_tabs && c == '\t')
  262.                break;
  263.          }
  264.          g_status.line_buff_len = len;
  265.          file->dirty = GLOBAL;
  266.          if (window->visible == TRUE)
  267.             show_changed_line( window );
  268.       }
  269.       len = g_status.line_buff_len;
  270.       ll_len =  (ll->line == NULL) ? 0 : ll->len;
  271.  
  272.  
  273.       assert( len < MAX_LINE_LENGTH );
  274.       assert( ll_len < MAX_LINE_LENGTH );
  275.  
  276.       net_change = len - ll_len;
  277.  
  278.       if (ll_len != len  ||  ll->line == NULL) {
  279.          /*
  280.           * let malloc space for the new line before we free the old line.
  281.           */
  282.          p = my_malloc( len, &rc );
  283.          if (rc == ERROR)
  284.             error( WARNING, window->bottom_line, main4 );
  285.  
  286.          /*
  287.           * free the space taken up by current line in far heap.
  288.           */
  289.          if (rc != ERROR  &&  ll->line != NULL)
  290.             my_free( ll->line );
  291.       } else
  292.          p = ll->line;
  293.  
  294.       if (rc != ERROR) {
  295.          if (len > 0)
  296.             _fmemcpy( p, g_status.line_buff, len );
  297.          ll->line = p;
  298.          ll->len = len;
  299.  
  300.          if (net_change != 0) {
  301.             for (wp=g_status.window_list; wp != NULL; wp=wp->next) {
  302.                if (wp->file_info == file && wp != window)
  303.                   if (wp->rline > window->rline)
  304.                      wp->bin_offset += net_change;
  305.             }
  306.          }
  307.  
  308.          file->modified = TRUE;
  309.          show_avail_mem( );
  310.       }
  311.    }
  312.    g_status.copied = FALSE;
  313.    return( rc );
  314. }
  315.  
  316.  
  317. /*
  318.  * Name:    un_copy_tab_buffer
  319.  * Purpose: To copy the tab buffer line the main text buffer
  320.  * Date:    October 31, 1992
  321.  * Passed:  line_number:  line number to copy line tab out buffer
  322.  *          window:       pointer to current window
  323.  */
  324. int  un_copy_tab_buffer( line_list_ptr ll, WINDOW *window )
  325. {
  326. text_ptr p;
  327. int  len;               /* length of current line buffer text */
  328. int  net_change;
  329. int  rc;
  330. file_infos *file;
  331. WINDOW *wp;
  332.  
  333.    rc = OK;
  334.    file = window->file_info;
  335.    /*
  336.     * file has changed.  lets create the back_up if needed
  337.     */
  338.    if (mode.do_backups == TRUE) {
  339.       window->file_info->modified = TRUE;
  340.       rc = backup_file( window );
  341.    }
  342.  
  343.    len = g_status.tabout_buff_len;
  344.  
  345.    assert( len >= 0 );
  346.    assert( len < MAX_LINE_LENGTH );
  347.    assert( ll->len >= 0 );
  348.    assert( ll->len < MAX_LINE_LENGTH );
  349.  
  350.    /*
  351.     * if the far heap has run out of space, then only part of the
  352.     *  current line can be moved back into the far heap. Warn the user
  353.     *  that some of the current line has been lost.
  354.     */
  355.    p = my_malloc( len, &rc );
  356.    if (rc == ERROR)
  357.       error( WARNING, window->bottom_line, main4 );
  358.  
  359.    if (rc == OK) {
  360.       net_change = len - ll->len;
  361.  
  362.       if (ll->line != NULL)
  363.          my_free( ll->line );
  364.       if (len > 0)
  365.          _fmemcpy( p, g_status.line_buff, len );
  366.       ll->line = p;
  367.       ll->len  = len;
  368.  
  369.       if (net_change != 0) {
  370.          for (wp=g_status.window_list; wp != NULL; wp=wp->next) {
  371.             if (wp->file_info == file && wp != window)
  372.                if (wp->rline > window->rline)
  373.                   wp->bin_offset += net_change;
  374.          }
  375.       }
  376.  
  377.       file->modified = TRUE;
  378.    }
  379.    return( rc );
  380. }
  381.  
  382.  
  383. /*
  384.  * Name:    load_undo_buffer
  385.  * Purpose: To copy the cursor line to the undo buffer.
  386.  * Date:    September 26, 1991
  387.  * Passed:  file:          pointer to file
  388.  *          line_to_undo:  pointer to line in file to save
  389.  * Notes:   save the last mode.undo_max lines in a stack.  when we overflow
  390.  *           the stack, dump the oldest line.
  391.  */
  392. void load_undo_buffer( file_infos *file, text_ptr line_to_undo, int len )
  393. {
  394. int  rc;
  395. text_ptr l;
  396. line_list_ptr temp_ll;
  397.  
  398.    rc = OK;
  399.    if (file->undo_count >= mode.undo_max) {
  400.       --file->undo_count;
  401.       temp_ll = file->undo_bot->prev;
  402.       temp_ll->prev->next = file->undo_bot;
  403.       file->undo_bot->prev = temp_ll->prev;
  404.       if (temp_ll->line != NULL)
  405.          my_free( temp_ll->line );
  406.    } else
  407.       temp_ll = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  408.  
  409.    assert( len >= 0 );
  410.    assert( len < MAX_LINE_LENGTH );
  411.  
  412.    l = my_malloc( len, &rc );
  413.  
  414.    if (rc == ERROR) {
  415.       if (l != NULL)
  416.          my_free( l );
  417.       if (temp_ll != NULL)
  418.          my_free( temp_ll );
  419.    } else {
  420.       if (len > 0)
  421.          _fmemcpy( l, line_to_undo, len );
  422.       temp_ll->line  = l;
  423.       temp_ll->len   = len;
  424.       temp_ll->dirty = TRUE;
  425.  
  426.       temp_ll->prev = NULL;
  427.       temp_ll->next = file->undo_top;
  428.       file->undo_top->prev = temp_ll;
  429.       file->undo_top = temp_ll;
  430.  
  431.       ++file->undo_count;
  432.    }
  433. }
  434.  
  435.  
  436. /*
  437.  * Name:    set_prompt
  438.  * Purpose: To display a prompt, highlighted, at the bottom of the screen.
  439.  * Date:    October 1, 1989
  440.  * Passed:  prompt: prompt to be displayed
  441.  *          line:   line to display prompt
  442.  */
  443. void set_prompt( char *prompt, int line )
  444. {
  445. register int prompt_col;
  446.  
  447.    /*
  448.     * work out where the answer should go
  449.     */
  450.    prompt_col = strlen( prompt );
  451.  
  452.    assert( prompt_col <= MAX_COLS );
  453.  
  454.    /*
  455.     * output the prompt
  456.     */
  457.    s_output( prompt, line, 0, g_display.message_color );
  458.    eol_clear( prompt_col, line, g_display.message_color );
  459.  
  460.    /*
  461.     * put cursor at end of prompt
  462.     */
  463.    xygoto( prompt_col, line );
  464. }
  465.  
  466.  
  467. /*
  468.  * Name:    get_name
  469.  * Purpose: To prompt the user and read the string entered in response.
  470.  * Date:    June 5, 1992
  471.  * Passed:  prompt: prompt to offer the user
  472.  *          line:   line to display prompt
  473.  *          name:   default answer
  474.  *          color:  color to display prompt
  475.  * Returns: name:   user's answer
  476.  *          OK if user entered something
  477.  *          ERROR if user aborted the command
  478.  * Notes:   with the addition of macros in tde, this function became a little
  479.  *           more complicated.  we have to deal with both executing macros
  480.  *           and macros that are the user uses when entering normal text
  481.  *           at the prompt.  i call these local and global macros.  a global
  482.  *           macro is when this function is called from a running macro.
  483.  *           the running macro can enter text and return from this function
  484.  *           w/o any action from the user.  a local macro is when the user
  485.  *           presses a key inside this function, which happens quite often
  486.  *           when keys are assigned to ASCII and Extended ASCII characters.
  487.  */
  488. int  get_name( char *prompt, int line, char *name, int color )
  489. {
  490. int  col;               /* cursor column for answer */
  491. int  c;                 /* character user just typed */
  492. char *cp;               /* cursor position in answer */
  493. char *answer;           /* user's answer */
  494. int first = TRUE;       /* first character typed */
  495. register int len;       /* length of answer */
  496. int  plen;              /* length of prompt */
  497. int  func;              /* function of key pressed */
  498. int  stop;              /* flag to stop getting characters */
  499. char *p;                /* for copying text in answer */
  500. char buffer[MAX_COLS+2];/* line on which name is being entered */
  501. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  502. int  normal;
  503. int  local_macro = FALSE;
  504. int  next;
  505.  
  506.    /*
  507.     * set up prompt and default
  508.     */
  509.    assert( strlen( prompt ) < MAX_COLS );
  510.    assert( strlen( name )   < MAX_COLS );
  511.  
  512.    strcpy( buffer, prompt );
  513.    plen = strlen( prompt );
  514.    answer = buffer + plen;
  515.    strcpy( answer, name );
  516.  
  517.    /*
  518.     * let user edit default string
  519.     */
  520.    len = strlen( answer );
  521.    col = strlen( buffer );
  522.    g_status.prompt_line = line;
  523.    g_status.prompt_col = col;
  524.    cp = answer + len;
  525.    normal = g_display.text_color;
  526.    save_screen_line( 0, line, line_buff );
  527.    s_output( buffer, line, 0, color );
  528.    eol_clear( col, line, normal );
  529.    for (stop = FALSE; stop == FALSE;) {
  530.       xygoto( col, line );
  531.       if (g_status.macro_executing) {
  532.          next = g_status.macro_next;
  533.          g_status.macro_next = macro.strokes[g_status.macro_next].next;
  534.          if (g_status.macro_next != -1) {
  535.             c = macro.strokes[g_status.macro_next].key;
  536.             func = getfunc( c );
  537.             if (func == PlayBack) {
  538.                stop = TRUE;
  539.                g_status.macro_next = next;
  540.             }
  541.          } else {
  542.             c = 0x100;
  543.             func = AbortCommand;
  544.             stop = TRUE;
  545.          }
  546.       } else {
  547.          if (local_macro == FALSE) {
  548.             c = getkey( );
  549.             func = getfunc( c );
  550.  
  551.             /*
  552.              * User may have redefined the Enter and ESC keys.  Make the Enter
  553.              *  key perform a Rturn in this function. Make the ESC key do an
  554.              *  AbortCommand.
  555.              */
  556.             if (c == RTURN)
  557.                func = Rturn;
  558.             else if (c == ESC)
  559.                func = AbortCommand;
  560.  
  561.             if (func == PlayBack) {
  562.                local_macro = TRUE;
  563.                next = macro.first_stroke[ c-256 ];
  564.                c = macro.strokes[next].key;
  565.                func = getfunc( c );
  566.                next = macro.strokes[next].next;
  567.             } else {
  568.                g_status.key_pressed = c;
  569.                record_keys( line );
  570.             }
  571.          } else {
  572.             if (next != -1) {
  573.                c = macro.strokes[next].key;
  574.                next = macro.strokes[next].next;
  575.             } else {
  576.                local_macro = FALSE;
  577.                c = 0x100;
  578.             }
  579.             func = getfunc( c );
  580.          }
  581.       }
  582.       switch (func) {
  583.          case ToggleSearchCase :
  584.             mode.search_case = mode.search_case == IGNORE ? MATCH : IGNORE;
  585.             build_boyer_array( );
  586.             show_search_case( );
  587.             break;
  588.          case Rturn       :
  589.          case NextLine    :
  590.          case BegNextLine :
  591.             answer[len] = '\0';
  592.             assert( strlen( answer ) < MAX_COLS );
  593.             strcpy( name, answer );
  594.             /*
  595.              * finished
  596.              */
  597.             stop = TRUE;
  598.             break;
  599.          case BackSpace :
  600.             /*
  601.              * delete to left of cursor
  602.              */
  603.             if (cp > answer) {
  604.                for (p=cp-1; p < answer+len; p++) {
  605.                   *p = *(p+1);
  606.                }
  607.                --len;
  608.                --col;
  609.                --cp;
  610.                c_output( ' ', plen+len, line, normal );
  611.                s_output( cp, line, col, color );
  612.                *(answer + len) = '\0';
  613.             }
  614.             break;
  615.          case DeleteChar :
  616.             /*
  617.              * delete char under cursor
  618.              */
  619.             if (*cp) {
  620.                for (p=cp; p < answer+len; p++) {
  621.                   *p = *(p+1);
  622.                }
  623.                --len;
  624.                c_output( ' ', plen+len, line, normal );
  625.                s_output( cp, line, col, color );
  626.                *(answer + len) = '\0';
  627.             }
  628.             break;
  629.          case DeleteLine :
  630.             /*
  631.              * delete current line
  632.              */
  633.             col = plen;
  634.             cp = answer;
  635.             *cp = '\0';
  636.             len = 0;
  637.             eol_clear( col, line, normal );
  638.             break;
  639.          case AbortCommand :
  640.             stop = TRUE;
  641.             break;
  642.          case CharLeft :
  643.             /*
  644.              * move cursor left
  645.              */
  646.             if (cp > answer) {
  647.                col--;
  648.                cp--;
  649.             }
  650.             break;
  651.          case CharRight :
  652.             /*
  653.              * move cursor right
  654.              */
  655.             if (*cp) {
  656.                col++;
  657.                cp++;
  658.              }
  659.              break;
  660.          case BegOfLine :
  661.             /*
  662.              * move cursor to start of line
  663.              */
  664.             col = plen;
  665.             cp = answer;
  666.             break;
  667.          case EndOfLine :
  668.             /*
  669.              * move cursor to end of line
  670.              */
  671.             col = plen + len;
  672.             cp = answer + len;
  673.             break;
  674.          default :
  675.             if (c < 0x100) {
  676.                /*
  677.                 * insert character at cursor
  678.                 */
  679.                if (first) {
  680.                   /*
  681.                    * delete previous answer
  682.                    */
  683.                   col = plen;
  684.                   cp = answer;
  685.                   *cp = '\0';
  686.                   len = 0;
  687.                   eol_clear( col, line, normal );
  688.                }
  689.  
  690.                /*
  691.                 * insert new character
  692.                 */
  693.                if (col < g_display.ncols-1) {
  694.                   if (*cp == '\0') {
  695.                      ++len;
  696.                      *(answer + len) = '\0';
  697.                   }
  698.                   *cp = (char)c;
  699.                   c_output( c, col, line, color );
  700.                   ++cp;
  701.                   ++col;
  702.                }
  703.             }
  704.             break;
  705.       }
  706.       first = FALSE;
  707.    }
  708.    restore_screen_line( 0, line, line_buff );
  709.    return( func == AbortCommand ? ERROR : OK );
  710. }
  711.  
  712.  
  713. /*
  714.  * Name:    get_sort_order
  715.  * Purpose: To prompt the user and get sort direction
  716.  * Date:    June 5, 1992
  717.  * Passed:  window
  718.  * Returns: OK if user entered something
  719.  *          ERROR if user aborted the command
  720.  */
  721. int  get_sort_order( WINDOW *window )
  722. {
  723. register int c;
  724. int  col;
  725. char line_buff[(MAX_COLS+1)*2];         /* buffer for char and attribute  */
  726.  
  727.    save_screen_line( 0, window->bottom_line, line_buff );
  728.    /*
  729.     * sort ascending or descending
  730.     */
  731.    s_output( utils4, window->bottom_line, 0, g_display.message_color );
  732.    c = strlen( utils4 );
  733.    eol_clear( c, window->bottom_line, g_display.text_color );
  734.    xygoto( c, window->bottom_line );
  735.    do {
  736.       c = getkey( );
  737.       col = getfunc( c );
  738.       if (c == ESC)
  739.          col = AbortCommand;
  740.    } while (col != AbortCommand  &&  c != 'A'  &&  c != 'a'  &&
  741.             c != 'D'  &&  c != 'd');
  742.    switch ( c ) {
  743.       case 'A' :
  744.       case 'a' :
  745.          sort.direction = ASCENDING;
  746.          break;
  747.       case 'D' :
  748.       case 'd' :
  749.          sort.direction = DESCENDING;
  750.          break;
  751.       default  :
  752.          col = AbortCommand;
  753.          break;
  754.    }
  755.    restore_screen_line( 0, window->bottom_line, line_buff );
  756.    return( col == AbortCommand ? ERROR : OK );
  757. }
  758.  
  759.  
  760. /*
  761.  * Name:    get_replace_direction
  762.  * Purpose: To prompt the user and get replace string direction
  763.  * Date:    October 31, 1992
  764.  * Passed:  window
  765.  * Returns: OK if user entered something
  766.  *          ERROR if user aborted the command
  767.  */
  768. int  get_replace_direction( WINDOW *window )
  769. {
  770. register int c;
  771. int  col;
  772. char line_buff[(MAX_COLS+1)*2];         /* buffer for char and attribute  */
  773.  
  774.    save_screen_line( 0, window->bottom_line, line_buff );
  775.    /*
  776.     * replace forward or backward
  777.     */
  778.    s_output( utils5, window->bottom_line, 0, g_display.message_color );
  779.    c = strlen( utils5 );
  780.    eol_clear( c, window->bottom_line, g_display.text_color );
  781.    xygoto( c, window->bottom_line );
  782.    do {
  783.       c = getkey( );
  784.       col = getfunc( c );
  785.       if (c == ESC)
  786.          col = AbortCommand;
  787.    } while (col != AbortCommand  &&  c != 'F'  &&  c != 'f'  &&
  788.             c != 'B'  &&  c != 'b');
  789.    switch ( c ) {
  790.       case 'F' :
  791.       case 'f' :
  792.          c = FORWARD;
  793.          break;
  794.       case 'B' :
  795.       case 'b' :
  796.          c = BACKWARD;
  797.          break;
  798.       default  :
  799.          c = ERROR;
  800.    }
  801.    restore_screen_line( 0, window->bottom_line, line_buff );
  802.    return( col == AbortCommand ? ERROR : c );
  803. }
  804.  
  805.  
  806. /*
  807.  * Name:    get_yn
  808.  * Purpose: To input a response of yes or no.
  809.  * Date:    October 1, 1989
  810.  * Returns: the user's answer.  A_??? - see tdestr.h
  811.  */
  812. int  get_yn( void )
  813. {
  814. int  c;                 /* the user's response */
  815. register int rc;        /* return code */
  816.  
  817.    do {
  818.       c = getkey( );
  819.       rc = getfunc( c );
  820.       if (c== ESC)
  821.          rc = AbortCommand;
  822.    } while (rc != AbortCommand  &&  c != 'Y'  &&  c != 'y'  &&
  823.             c != 'N'  &&  c != 'n');
  824.    if (rc == AbortCommand || c == ESC)
  825.       rc = ERROR;
  826.    else {
  827.       switch ( c ) {
  828.          case 'Y' :
  829.          case 'y' :
  830.             rc = A_YES;
  831.             break;
  832.          case 'N' :
  833.          case 'n' :
  834.             rc = A_NO;
  835.             break;
  836.       }
  837.    }
  838.    return( rc );
  839. }
  840.  
  841.  
  842. /*
  843.  * Name:    get_lr
  844.  * Purpose: To input a response of yes or no.
  845.  * Date:    June 1, 1991
  846.  * Returns: the user's answer, LEFT or RIGHT.
  847.  */
  848. int  get_lr( void )
  849. {
  850. int  c;                 /* the user's response */
  851. register int rc;        /* return code */
  852.  
  853.    for (rc=OK; rc == OK;) {
  854.       c = getkey( );
  855.       if (getfunc( c ) == AbortCommand || c == ESC)
  856.          rc = ERROR;
  857.       else {
  858.          switch ( c ) {
  859.             case 'L' :
  860.             case 'l' :
  861.                rc = LEFT;
  862.                break;
  863.             case 'R' :
  864.             case 'r' :
  865.                rc = RIGHT;
  866.                break;
  867.          }
  868.       }
  869.    }
  870.    return( rc );
  871. }
  872.  
  873.  
  874. /*
  875.  * Name:    get_bc
  876.  * Purpose: To input a response of beginning or current cursor postion
  877.  * Date:    October 31, 1992
  878.  * Returns: the user's answer, Beginning or Current.
  879.  */
  880. int  get_bc( void )
  881. {
  882. int  c;                 /* the user's response */
  883. register int rc;        /* return code */
  884.  
  885.    for (rc=OK; rc == OK;) {
  886.       c = getkey( );
  887.       if (getfunc( c ) == AbortCommand || c == ESC)
  888.          rc = ERROR;
  889.       else {
  890.          switch ( c ) {
  891.             case 'B' :
  892.             case 'b' :
  893.                rc = BEGINNING;
  894.                break;
  895.             case 'C' :
  896.             case 'c' :
  897.                rc = CURRENT;
  898.                break;
  899.          }
  900.       }
  901.    }
  902.    return( rc );
  903. }
  904.  
  905.  
  906. /*
  907.  * Name:    get_oa
  908.  * Purpose: To input a response of overwrite or append.
  909.  * Date:    October 1, 1989
  910.  * Returns: the user's answer.  A_??? - see tdestr.h
  911.  */
  912. int  get_oa( void )
  913. {
  914. int  c;                 /* the user's response */
  915. register int rc;        /* return code */
  916. int  func;
  917.  
  918.    rc = 0;
  919.    while (rc != AbortCommand && rc != A_OVERWRITE && rc != A_APPEND) {
  920.       c = getkey( );
  921.       func = getfunc( c );
  922.       if (func == AbortCommand || c == ESC)
  923.          rc = AbortCommand;
  924.       switch ( c ) {
  925.          case 'O' :
  926.          case 'o' :
  927.             rc = A_OVERWRITE;
  928.             break;
  929.          case 'A' :
  930.          case 'a' :
  931.             rc = A_APPEND;
  932.             break;
  933.       }
  934.    }
  935.    return( rc );
  936. }
  937.  
  938.  
  939. /*
  940.  * Name:    show_eof
  941.  * Purpose: display eof message
  942.  * Date:    September 16, 1991
  943.  * Notes:   line:  ususally, line to is display "<=== eof ===>"
  944.  */
  945. void show_eof( WINDOW *window )
  946. {
  947. register int color;
  948. char temp[MAX_COLS+2];
  949.  
  950.    assert( strlen( mode.eof ) < MAX_COLS );
  951.  
  952.    strcpy( temp, mode.eof );
  953.    color = window->end_col + 1 - window->start_col;
  954.    if (strlen( temp ) > (unsigned)color)
  955.       temp[color] = '\0';
  956.    color = g_display.eof_color;
  957.    window_eol_clear( window, color );
  958.    s_output( temp, window->cline, window->start_col, color );
  959. }
  960.  
  961.  
  962. /*
  963.  * Name:    display_current_window
  964.  * Purpose: display text in current window
  965.  * Date:    June 5, 1991
  966.  * Passed:  window:  pointer to current window
  967.  * Notes:   use a temporary window structure, "w", to do the dirty work.
  968.  */
  969. void display_current_window( WINDOW *window )
  970. {
  971. int  count;     /* number of lines updated so far */
  972. int  number;    /* number of lines visible in window */
  973. register int i; /* register variable */
  974. WINDOW w;       /* scratch window structure */
  975. int  curl;      /* current line on screen, window->cline */
  976. int  eof;
  977.  
  978.    /*
  979.     * initialize the scratch variables
  980.     */
  981.    number = window->bottom_line - ((window->top_line + window->ruler) - 1);
  982.    count  = window->cline - (window->top_line + window->ruler);
  983.    dup_window_info( &w, window );
  984.  
  985.    w.cline -= count;
  986.    w.rline -= count;
  987.    for (eof=count; eof > 0; eof--)
  988.       w.ll = w.ll->prev;
  989.  
  990.  
  991.    /*
  992.     * start at the top of the window and display a window full of text
  993.     */
  994.    eof = FALSE;
  995.    curl = window->cline;
  996.    for (i=number; i>0; i--) {
  997.       if (w.ll->len != EOF) {
  998.          /*
  999.           * if this is window->cline, do not show the line because we
  1000.           *  show the curl at the end of this function.  don't show it twice
  1001.           */
  1002.          if (w.cline != curl)
  1003.             update_line( &w );
  1004.          w.ll = w.ll->next;
  1005.       } else if (eof == FALSE) {
  1006.          show_eof( &w );
  1007.          eof = TRUE;
  1008.       } else
  1009.          window_eol_clear( &w, COLOR_TEXT );
  1010.       ++w.cline;
  1011.       ++w.rline;
  1012.    }
  1013.    show_asterisk( window );
  1014.    show_curl_line( window );
  1015. }
  1016.  
  1017.  
  1018. /*
  1019.  * Name:    redraw_screen
  1020.  * Purpose: display all visible windows, modes, and headers
  1021.  * Date:    June 5, 1991
  1022.  * Passed:  window:  pointer to current window
  1023.  */
  1024. int  redraw_screen( WINDOW *window )
  1025. {
  1026. register WINDOW *above;        /* window above current */
  1027. register WINDOW *below;        /* window below current */
  1028.  
  1029.    cls( );
  1030.    /*
  1031.     * display the current window
  1032.     */
  1033.    redraw_current_window( window );
  1034.  
  1035.    /*
  1036.     * now update all the other windows
  1037.     */
  1038.    above = below = window;
  1039.    while (above->prev || below->next) {
  1040.       if (above->prev) {
  1041.          above = above->prev;
  1042.          redraw_current_window( above );
  1043.       }
  1044.       if (below->next) {
  1045.          below = below->next;
  1046.          redraw_current_window( below );
  1047.       }
  1048.    }
  1049.    window->file_info->dirty = FALSE;
  1050.    show_modes( );
  1051.    return( OK );
  1052. }
  1053.  
  1054.  
  1055. /*
  1056.  * Name:    redraw_current_window
  1057.  * Purpose: redraw all info in window
  1058.  * Date:    July 13, 1991
  1059.  * Passed:  window:  pointer to current window
  1060.  */
  1061. void redraw_current_window( WINDOW *window )
  1062. {
  1063.  
  1064.    /*
  1065.     * display the current window
  1066.     */
  1067.    if (window->visible) {
  1068.       display_current_window( window );
  1069.       show_window_header( window );
  1070.       show_ruler( window );
  1071.       show_ruler_pointer( window );
  1072.       if (window->vertical)
  1073.          show_vertical_separator( window );
  1074.    }
  1075. }
  1076.  
  1077.  
  1078. /*
  1079.  * Name:    show_changed_line
  1080.  * Purpose: Only one line was changed in file, just show it
  1081.  * Date:    June 5, 1991
  1082.  * Passed:  window:  pointer to current window
  1083.  */
  1084. void show_changed_line( WINDOW *window )
  1085. {
  1086. WINDOW *above;                  /* window above current */
  1087. WINDOW *below;                  /* window below current */
  1088. WINDOW w;                       /* scratch window structure */
  1089. long changed_line;              /* line number in file that was changed */
  1090. long top_line, bottom_line;     /* top and bottom line in file on screen */
  1091. int  line_on_screen;            /* is changed line on screen? */
  1092. file_infos *file;               /* file pointer */
  1093.  
  1094.    file = window->file_info;
  1095.    if ((file->dirty == LOCAL || file->dirty == GLOBAL) && window->visible)
  1096.       show_curl_line( window );
  1097.    changed_line = window->rline;
  1098.  
  1099.    /*
  1100.     * now update the line in all other windows
  1101.     */
  1102.    if (file->dirty != LOCAL) {
  1103.       above = below = window;
  1104.       while (above->prev || below->next) {
  1105.          if (above->prev) {
  1106.             above = above->prev;
  1107.             dup_window_info( &w, above );
  1108.          } else if (below->next) {
  1109.             below = below->next;
  1110.             dup_window_info( &w, below );
  1111.          }
  1112.  
  1113.          /*
  1114.           * is this window the changed file and is it visible?
  1115.           */
  1116.          if (w.file_info == file && w.visible) {
  1117.  
  1118.             /*
  1119.              * calculate file lines at top and bottom of screen.
  1120.              * the changed line may not be the curl in other windows.
  1121.              */
  1122.             line_on_screen = FALSE;
  1123.             top_line = w.rline - (w.cline - (w.top_line + w.ruler));
  1124.             bottom_line = w.rline + (w.bottom_line - w.cline);
  1125.             if (changed_line == w.rline)
  1126.                line_on_screen = CURLINE;
  1127.             else if (changed_line < w.rline && changed_line >= top_line) {
  1128.                line_on_screen = NOTCURLINE;
  1129.                while (w.rline > changed_line) {
  1130.                   w.ll = w.ll->prev;
  1131.                   --w.rline;
  1132.                   --w.cline;
  1133.                }
  1134.             } else if (changed_line > w.rline && changed_line <= bottom_line) {
  1135.                line_on_screen = NOTCURLINE;
  1136.                while (w.rline < changed_line) {
  1137.                   w.ll = w.ll->next;
  1138.                   ++w.rline;
  1139.                   ++w.cline;
  1140.                }
  1141.             }
  1142.  
  1143.             /*
  1144.              * display the changed line if on screen
  1145.              */
  1146.             if (line_on_screen == NOTCURLINE)
  1147.                update_line( &w );
  1148.             else if (line_on_screen == CURLINE)
  1149.                show_curl_line( &w );
  1150.          }
  1151.       }
  1152.    }
  1153.    file->dirty = FALSE;
  1154. }
  1155.  
  1156.  
  1157. /*
  1158.  * Name:    show_curl_line
  1159.  * Purpose: show current line in curl color
  1160.  * Date:    January 16, 1992
  1161.  * Passed:  window:  pointer to current window
  1162.  */
  1163. void show_curl_line( WINDOW *window )
  1164. {
  1165. int  text_color;
  1166. int  dirty_color;
  1167.  
  1168.    text_color = g_display.text_color;
  1169.    dirty_color = g_display.dirty_color;
  1170.    g_display.dirty_color = g_display.text_color = g_display.curl_color;
  1171.    update_line( window );
  1172.    g_display.text_color = text_color;
  1173.    g_display.dirty_color = dirty_color;
  1174. }
  1175.  
  1176.  
  1177. /*
  1178.  * Name:    dup_window_info
  1179.  * Purpose: Copy window info from one window pointer to another
  1180.  * Date:    June 5, 1991
  1181.  * Passed:  dw: destination window
  1182.  *          sw: source window
  1183.  */
  1184. void dup_window_info( WINDOW *dw, WINDOW *sw )
  1185. {
  1186.    memcpy( dw, sw, sizeof( WINDOW ) );
  1187. }
  1188.  
  1189.  
  1190. /*
  1191.  * Name:    adjust_windows_cursor
  1192.  * Purpose: A change has been made, make sure pointers are not ahead of
  1193.  *           or behind file.
  1194.  * Date:    June 5, 1991
  1195.  * Passed:  window:       pointer to current window
  1196.  *          line_change:  number of lines add to or subtracted from file
  1197.  * Notes:   If a file has been truncated in one window and there is another
  1198.  *           window open to the same file and its current line is near the
  1199.  *           end, the current line is reset to the last line of the file.
  1200.  */
  1201. void adjust_windows_cursor( WINDOW *window, long line_change )
  1202. {
  1203. register WINDOW *next;
  1204. long i;
  1205. file_infos *file;
  1206. MARKER *marker;
  1207. long length;
  1208.  
  1209.    file = window->file_info;
  1210.    length = file->length;
  1211.    next = g_status.window_list;
  1212.    while (next != NULL) {
  1213.       if (next != window) {
  1214.          if (next->file_info == file) {
  1215.             if (next->rline > length + 1) {
  1216.                next->rline = length;
  1217.                next->ll    = file->line_list_end;
  1218.                file->dirty = NOT_LOCAL;
  1219.             } else if (next->rline < 1) {
  1220.                next->rline = 1;
  1221.                next->cline = next->top_line + next->ruler;
  1222.                next->ll    = file->line_list;
  1223.                next->bin_offset = 0;
  1224.                file->dirty = NOT_LOCAL;
  1225.             }
  1226.             if (next->rline > window->rline  &&  line_change) {
  1227.                file->dirty = NOT_LOCAL;
  1228.                if (line_change < 0) {
  1229.                   for (i=line_change; i < 0 && next->ll->next != NULL; i++) {
  1230.                      next->bin_offset += next->ll->len;
  1231.                      next->ll = next->ll->next;
  1232.                   }
  1233.                } else if (line_change > 0) {
  1234.                   for (i=line_change; i > 0 && next->ll->prev != NULL; i--) {
  1235.                      next->ll = next->ll->prev;
  1236.                      next->bin_offset -= next->ll->len;
  1237.                   }
  1238.                }
  1239.             }
  1240.             if (next->rline < (next->cline -(next->top_line+next->ruler-1))) {
  1241.                next->cline = (int)next->rline+(next->top_line+next->ruler)-1;
  1242.                file->dirty = NOT_LOCAL;
  1243.             }
  1244.          }
  1245.       }
  1246.       next = next->next;
  1247.    }
  1248.  
  1249.    /*
  1250.     * now adjust any markers.
  1251.     */
  1252.    for (i=0; i<3; i++) {
  1253.       marker = &file->marker[ (int) i ];
  1254.       if (marker->rline > window->rline) {
  1255.          marker->rline += line_change;
  1256.          if (marker->rline < 1L)
  1257.             marker->rline = 1L;
  1258.          else if (marker->rline > length)
  1259.             marker->rline = length;
  1260.       }
  1261.    }
  1262. }
  1263.  
  1264.  
  1265. /*
  1266.  * Name:    first_non_blank
  1267.  * Purpose: To find the column of the first non-blank character
  1268.  * Date:    June 5, 1991
  1269.  * Passed:  s:    the string to search
  1270.  *          len:  length of string
  1271.  * Returns: the first non-blank column
  1272.  */
  1273. int  first_non_blank( text_ptr s, int len )
  1274. {
  1275. register int count = 0;
  1276.  
  1277.    if (s != NULL) {
  1278.       if (mode.inflate_tabs) {
  1279.          for (; len > 0 && (*s == ' ' || *s == '\t'); s++, len--) {
  1280.             if (*s != '\t')
  1281.                ++count;
  1282.             else
  1283.                count += mode.ptab_size - (count % mode.ptab_size);
  1284.          }
  1285.       } else {
  1286.          while (len-- > 0  &&  *s++ == ' ')
  1287.            ++count;
  1288.       }
  1289.    }
  1290.    return( count );
  1291. }
  1292.  
  1293.  
  1294. /*
  1295.  * Name:    find_end
  1296.  * Purpose: To find the last character in a line
  1297.  * Date:    October 31, 1992
  1298.  * Passed:  s:    the string to search
  1299.  *          len:  length of string
  1300.  * Returns: the first non-blank column
  1301.  */
  1302. int  find_end( text_ptr s, int len )
  1303. {
  1304. register int count = 0;
  1305.  
  1306.    if (s != NULL) {
  1307.       if (mode.inflate_tabs) {
  1308.          for (;len > 0; s++, len--) {
  1309.             if (*s == '\t')
  1310.                count += mode.ptab_size - (count % mode.ptab_size);
  1311.             else
  1312.                ++count;
  1313.          }
  1314.       } else
  1315.          count = len;
  1316.    }
  1317.    return( count );
  1318. }
  1319.  
  1320.  
  1321. /*
  1322.  * Name:    is_line_blank
  1323.  * Purpose: is line empty or does it only contain spaces?
  1324.  * Date:    November 28, 1991
  1325.  * Passed:  s:    the string to search
  1326.  *          len:  length of string
  1327.  * Returns: TRUE if line is blank or FALSE if something is in line
  1328.  */
  1329. int is_line_blank( text_ptr s, int len )
  1330. {
  1331.    if (s != NULL) {
  1332.       if (mode.inflate_tabs) {
  1333.         while (len > 0  &&  (*s == ' ' || *s == '\t')) {
  1334.            ++s;
  1335.            --len;
  1336.         }
  1337.       } else {
  1338.          while (len > 0  &&  *s == ' ') {
  1339.             ++s;
  1340.             --len;
  1341.          }
  1342.       }
  1343.    } else
  1344.       len = 0;
  1345.    return( len == 0 );
  1346. }
  1347.  
  1348.  
  1349. /*
  1350.  * Name:    page_up
  1351.  * Purpose: To move the cursor one page up the window
  1352.  * Date:    June 5, 1991
  1353.  * Passed:  window:  pointer to current window
  1354.  * Notes:   The cursor line is moved back the required number of lines
  1355.  *           towards the start of the file.
  1356.  *          If the start of the file is reached, then movement stops.
  1357.  */
  1358. int  page_up( WINDOW *window )
  1359. {
  1360. int  i;                 /* count of lines scanned */
  1361. int  rc = OK;           /* default return code */
  1362. register WINDOW *win;   /* put window pointer in a register */
  1363. long number;
  1364. long len;
  1365.  
  1366.    win = window;
  1367.    entab_linebuff( );
  1368.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1369.       return( ERROR );
  1370.    if (win->rline != (win->cline - (win->top_line + win->ruler - 1))) {
  1371.       i = win->cline - (win->top_line + win->ruler - 1);
  1372.       number = win->rline;
  1373.       if (( win->rline - i) < win->page)
  1374.          win->rline = (win->cline-(win->top_line + win->ruler -1)) + win->page;
  1375.       win->rline -= win->page;
  1376.       for (len =0, i=(int)(number - win->rline); i>0; i--)
  1377.          if (win->ll->prev != NULL) {
  1378.             win->ll = win->ll->prev;
  1379.             len -= win->ll->len;
  1380.          }
  1381.       win->file_info->dirty = LOCAL;
  1382.       win->bin_offset += len;
  1383.    } else
  1384.       rc = ERROR;
  1385.    sync( win );
  1386.    return( rc );
  1387. }
  1388.  
  1389.  
  1390. /*
  1391.  * Name:    page_down
  1392.  * Purpose: To move the cursor one page down the window
  1393.  * Date:    June 5, 1991
  1394.  * Passed:  window:  pointer to current window
  1395.  * Notes:   The cursor line is moved forwards the required number of lines
  1396.  *           towards the end of the file.
  1397.  *          If the end of the file is reached, then movement stops.
  1398.  */
  1399. int  page_down( WINDOW *window )
  1400. {
  1401. int  i;                 /* count of lines scanned so far */
  1402. int  k;
  1403. int  rc = OK;
  1404. long len;
  1405. register WINDOW *win;  /* put window pointer in a register */
  1406. line_list_ptr p;
  1407.  
  1408.    win = window;
  1409.    entab_linebuff( );
  1410.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1411.       return( ERROR );
  1412.    p = win->ll;
  1413.    k = win->cline - (win->top_line + win->ruler);
  1414.    for (len=i=0; i < win->page && p->next != NULL; i++, k++, p=p->next)
  1415.       if (p->len != EOF)
  1416.          len += p->len;
  1417.    if (k >= win->page) {
  1418.       win->rline += i;
  1419.       win->cline = win->cline + i - win->page;
  1420.       win->bin_offset += len;
  1421.       win->ll = p;
  1422.       win->file_info->dirty = LOCAL;
  1423.    } else
  1424.       rc = ERROR;
  1425.    sync( win );
  1426.    return( rc );
  1427. }
  1428.  
  1429.  
  1430. /*
  1431.  * Name:    scroll_down
  1432.  * Purpose: scroll window down one line
  1433.  * Date:    June 5, 1991
  1434.  * Passed:  window:  pointer to current window
  1435.  * Notes:   If there is a line to scroll_down, make the window LOCAL dirty.
  1436.  *          We have to redraw the screen anyway, so don't update here.
  1437.  */
  1438. int  scroll_down( WINDOW *window )
  1439. {
  1440. int  rc = OK;
  1441. register WINDOW *win;   /* put window pointer in a register */
  1442.  
  1443.    win = window;
  1444.    entab_linebuff( );
  1445.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1446.       return( ERROR );
  1447.    if (win->cline == win->top_line + win->ruler) {
  1448.       if (win->ll->next != NULL) {
  1449.          ++win->rline;
  1450.          win->bin_offset += win->ll->len;
  1451.          win->ll = win->ll->next;
  1452.          win->file_info->dirty = LOCAL;
  1453.       } else
  1454.          rc = ERROR;
  1455.    } else {
  1456.       --win->cline;
  1457.       win->file_info->dirty = LOCAL;
  1458.    }
  1459.    sync( win );
  1460.    return( rc );
  1461. }
  1462.  
  1463.  
  1464. /*
  1465.  * Name:    scroll_up
  1466.  * Purpose: To scroll the window up one line
  1467.  * Date:    June 5, 1991
  1468.  * Passed:  window:  pointer to current window
  1469.  * Notes:   If this is the first page, then update screen here.  Else, make
  1470.  *           the window LOCAL dirty because we have to redraw screen.
  1471.  */
  1472. int  scroll_up( WINDOW *window )
  1473. {
  1474. int  rc = OK;
  1475. register WINDOW *win;   /* put window pointer in a register */
  1476.  
  1477.    win = window;
  1478.    entab_linebuff( );
  1479.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1480.       return( ERROR );
  1481.    if (win->rline > 1) {
  1482.       if (win->rline == (win->cline - (win->top_line + win->ruler - 1))) {
  1483.          if (!mode.sync)
  1484.             update_line( win );
  1485.          win->ll = win->ll->prev;
  1486.          win->bin_offset -= win->ll->len;
  1487.          --win->rline;
  1488.          --win->cline;
  1489.          if (!mode.sync)
  1490.             show_curl_line( win );
  1491.       } else {
  1492.          if (win->cline == win->bottom_line) {
  1493.             --win->rline;
  1494.             win->ll = win->ll->prev;
  1495.             win->bin_offset -= win->ll->len;
  1496.             win->file_info->dirty = LOCAL;
  1497.          } else {
  1498.             ++win->cline;
  1499.             win->file_info->dirty = LOCAL;
  1500.          }
  1501.       }
  1502.    } else
  1503.      rc = ERROR;
  1504.    sync( win );
  1505.    return( rc );
  1506. }
  1507.  
  1508.  
  1509. /*
  1510.  * Name:    pan_up
  1511.  * Purpose: To leave cursor on same logical line and scroll text up
  1512.  * Date:    September 1, 1991
  1513.  * Passed:  window:  pointer to current window
  1514.  * Notes:   If cursor is on first page then do not scroll.
  1515.  */
  1516. int  pan_up( WINDOW *window )
  1517. {
  1518. int  rc = OK;
  1519. register WINDOW *win;   /* put window pointer in a register */
  1520.  
  1521.    win = window;
  1522.    entab_linebuff( );
  1523.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1524.       return( ERROR );
  1525.  
  1526.    /*
  1527.     * see if cursor is on the first page. if it's not then pan_up.
  1528.     */
  1529.    if (win->rline != (win->cline+1 - (win->top_line + win->ruler))) {
  1530.       if (win->rline > 1) {
  1531.          --win->rline;
  1532.          win->ll = win->ll->prev;
  1533.          win->bin_offset -= win->ll->len;
  1534.          win->file_info->dirty = LOCAL;
  1535.       }
  1536.    } else
  1537.       rc = ERROR;
  1538.    sync( win );
  1539.    return( rc );
  1540. }
  1541.  
  1542.  
  1543. /*
  1544.  * Name:    pan_down
  1545.  * Purpose: To leave cursor on same logical line and scroll text down
  1546.  * Date:    September 1, 1991
  1547.  * Passed:  window:  pointer to current window
  1548.  * Notes:   If cursor is on last line in file then do not scroll.
  1549.  */
  1550. int  pan_down( WINDOW *window )
  1551. {
  1552. int  rc = OK;
  1553. register WINDOW *win;   /* put window pointer in a register */
  1554.  
  1555.    win = window;
  1556.    entab_linebuff( );
  1557.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1558.       return( ERROR );
  1559.    if (win->ll->len != EOF) {
  1560.       ++win->rline;
  1561.       win->bin_offset += win->ll->len;
  1562.       win->ll = win->ll->next;
  1563.       win->file_info->dirty = LOCAL;
  1564.    } else
  1565.       rc = ERROR;
  1566.    sync( win );
  1567.    return( rc );
  1568. }
  1569.  
  1570.  
  1571. /*
  1572.  * Name:    show_window_header
  1573.  * Purpose: show file stuff in window header
  1574.  * Date:    June 5, 1991
  1575.  * Passed:  window:  pointer to current window
  1576.  * Notes:   Clear line and display header in a lite bar
  1577.  */
  1578. void show_window_header( WINDOW *window )
  1579. {
  1580. char status_line[MAX_COLS+2];   /* status line at top of window */
  1581. register WINDOW *win;           /* put window pointer in a register */
  1582. int  len;
  1583.  
  1584.    win = window;
  1585.    len = win->vertical ? win->end_col + 1 - win->start_col : win->end_col;
  1586.  
  1587.    assert( len >= 0 );
  1588.    assert( len <= MAX_COLS );
  1589.  
  1590.    memset( status_line, ' ', len );
  1591.    status_line[len] = '\0';
  1592.    s_output( status_line, win->top_line-1, win->start_col,g_display.head_color);
  1593.    show_window_number_letter( win );
  1594.    show_window_fname( win );
  1595.    show_crlf_mode( win );
  1596.    show_size( win );
  1597.    show_line_col( win );
  1598. }
  1599.  
  1600.  
  1601. /*
  1602.  * Name:    show_window_number_letter
  1603.  * Purpose: show file number and letter of window in lite bar
  1604.  * Date:    June 5, 1991
  1605.  * Passed:  window:  pointer to current window
  1606.  */
  1607. void show_window_number_letter( WINDOW *window )
  1608. {
  1609. int  col;
  1610. char temp[10];
  1611. register WINDOW *win;   /* put window pointer in a register */
  1612.  
  1613.    win = window;
  1614.    col = win->start_col;
  1615.    s_output( "   ", win->top_line-1, col, g_display.head_color );
  1616.    itoa( win->file_info->file_no, temp, 10 );
  1617.    s_output( temp, win->top_line-1, strlen( temp ) > 1 ? col : col+1,
  1618.              g_display.head_color );
  1619.    c_output( win->letter, col+2, win->top_line-1, g_display.head_color );
  1620. }
  1621.  
  1622.  
  1623. /*
  1624.  * Name:    show_window_fname
  1625.  * Purpose: show file name in window header.
  1626.  * Date:    June 5, 1991
  1627.  * Passed:  window:  pointer to current window
  1628.  * Notes:   Clear name field and display name in a lite bar
  1629.  */
  1630. void show_window_fname( WINDOW *window )
  1631. {
  1632. char status_line[MAX_COLS+2];   /* status line at top of window */
  1633. register int  fattr;
  1634. char *p;
  1635. register WINDOW *win;          /* put window pointer in a register */
  1636. int  col;
  1637. int  len;
  1638.  
  1639.    win = window;
  1640.    col = win->start_col;
  1641.    len = win->vertical ? 11 : FNAME_LENGTH;
  1642.  
  1643.    assert( len >= 0 );
  1644.    assert( len <= MAX_COLS );
  1645.  
  1646.    memset( status_line, ' ', len );
  1647.    status_line[len] = '\0';
  1648.    s_output( status_line, win->top_line-1, col+5, g_display.head_color );
  1649.  
  1650.    assert( strlen( win->file_info->file_name ) < MAX_COLS );
  1651.  
  1652.    strcpy( status_line, win->file_info->file_name );
  1653.    p = status_line;
  1654.    if (win->vertical) {
  1655.       len = strlen( status_line );
  1656.       for (p=status_line+len;*(p-1) != ':' && *(p-1) != '\\' && p>status_line;)
  1657.          --p;
  1658.    } else {
  1659.       status_line[FNAME_LENGTH] = '\0';
  1660.       p = status_line;
  1661.    }
  1662.    s_output( p, win->top_line-1, col+5, g_display.head_color );
  1663.    if (!win->vertical) {
  1664.       fattr = win->file_info->file_attrib;
  1665.       p = status_line;
  1666.       *p++ = (char)(fattr & ARCHIVE   ? 'A' : '-');
  1667.       *p++ = (char)(fattr & SYSTEM    ? 'S' : '-');
  1668.       *p++ = (char)(fattr & HIDDEN    ? 'H' : '-');
  1669.       *p++ = (char)(fattr & READ_ONLY ? 'R' : '-');
  1670.       *p   = '\0';
  1671.       s_output( status_line, win->top_line-1, col+51, g_display.head_color );
  1672.    }
  1673. }
  1674.  
  1675.  
  1676. /*
  1677.  * Name:    show_crlf_mode
  1678.  * Purpose: display state of crlf flag
  1679.  * Date:    June 5, 1991
  1680.  */
  1681. void show_crlf_mode( WINDOW *window )
  1682. {
  1683. char status_line[MAX_COLS+2];   /* status line at top of window */
  1684.  
  1685.    if (!window->vertical) {
  1686.       switch (window->file_info->crlf) {
  1687.          case LF :
  1688.             strcpy( status_line, "lf  " );
  1689.             break;
  1690.          case CRLF :
  1691.             strcpy( status_line, "crlf" );
  1692.             break;
  1693.          case BINARY :
  1694.             strcpy( status_line, "BIN " );
  1695.             break;
  1696.          default :
  1697.             assert( FALSE );
  1698.       }
  1699.       s_output( status_line, window->top_line-1, window->start_col+56,
  1700.                 g_display.head_color );
  1701.    }
  1702. }
  1703.  
  1704.  
  1705. /*
  1706.  * Name:    show_size
  1707.  * Purpose: show number of lines in file
  1708.  * Date:    June 5, 1991
  1709.  * Passed:  window:  pointer to current window
  1710.  */
  1711. void show_size( WINDOW *window )
  1712. {
  1713. char csize[20];
  1714.  
  1715.    if (!window->vertical  &&  window->file_info->crlf != BINARY) {
  1716.       s_output( "       ", window->top_line-1, 61, g_display.head_color );
  1717.       ltoa( window->file_info->length, csize, 10 );
  1718.       s_output( csize, window->top_line-1, 61, g_display.head_color );
  1719.    }
  1720. }
  1721.  
  1722.  
  1723. /*
  1724.  * Name:    quit
  1725.  * Purpose: To close the current window without saving the current file.
  1726.  * Date:    June 5, 1991
  1727.  * Passed:  window:  pointer to current window
  1728.  * Notes:   If the file has been modified but not saved, then the user is
  1729.  *           given a second chance before the changes are discarded.
  1730.  *          Note that this is only necessary if this is the last window
  1731.  *           that refers to the file.  If another window still refers to
  1732.  *           the file, then the check can be left until later.
  1733.  */
  1734. int  quit( WINDOW *window )
  1735. {
  1736. int  prompt_line;
  1737. char line_buff[(MAX_COLS+2)*2]; /* buffer for char and attribute  */
  1738. register file_infos *file;
  1739. WINDOW *wp;
  1740. int  count = 0;
  1741. int  rc = OK;
  1742.  
  1743.    entab_linebuff( );
  1744.    if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  1745.       return( ERROR );
  1746.    prompt_line = window->bottom_line;
  1747.    file = window->file_info;
  1748.    for (wp=g_status.window_list; wp != NULL; wp=wp->next) {
  1749.       if (wp->file_info == file && wp->visible)
  1750.          ++count;
  1751.    }
  1752.    if (file->modified && count == 1) {
  1753.       save_screen_line( 0, prompt_line, line_buff );
  1754.       /*
  1755.        * abandon changes (y/n)
  1756.        */
  1757.       set_prompt( utils12, prompt_line );
  1758.       if (get_yn( ) != A_YES)
  1759.          rc = ERROR;
  1760.       restore_screen_line( 0, prompt_line, line_buff );
  1761.    }
  1762.  
  1763.    /*
  1764.     * remove window, allocate screen lines to other windows etc
  1765.     */
  1766.    if (rc == OK)
  1767.       finish( window );
  1768.    return( OK );
  1769. }
  1770.  
  1771.  
  1772. /*
  1773.  * Name:    move_up
  1774.  * Purpose: To move the cursor up one line
  1775.  * Date:    June 5, 1991
  1776.  * Passed:  window:  pointer to current window
  1777.  * Notes:   If the cursor is at the top of the window, then the file must
  1778.  *           be scrolled down.
  1779.  */
  1780. int  move_up( WINDOW *window )
  1781. {
  1782. int  rc = OK;
  1783. register WINDOW *win;   /* put window pointer in a register */
  1784. int  at_top = FALSE;    /* is cline at top of screen? */
  1785.  
  1786.    win = window;
  1787.    entab_linebuff( );
  1788.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1789.       return( ERROR );
  1790.  
  1791.    /*
  1792.     * if no previous line, give up
  1793.     */
  1794.    if (win->rline > 1) {
  1795.       if (win->cline == win->top_line + win->ruler) {
  1796.          win->file_info->dirty = LOCAL;
  1797.          at_top = TRUE;
  1798.       }
  1799.       if (!at_top)
  1800.          update_line( win );
  1801.       --win->rline;             /* ALWAYS decrement line counter */
  1802.       win->ll = win->ll->prev;
  1803.       win->bin_offset -= win->ll->len;
  1804.       if (!at_top) {
  1805.          --win->cline;          /* we aren't at top of screen - so move up */
  1806.          show_curl_line( win );
  1807.       }
  1808.    } else
  1809.       rc = ERROR;
  1810.    sync( win );
  1811.    return( rc );
  1812. }
  1813.  
  1814.  
  1815. /*
  1816.  * Name:    move_down
  1817.  * Purpose: To move the cursor down one line
  1818.  * Date:    June 5, 1991
  1819.  * Passed:  window:  pointer to current window
  1820.  * Notes:   If the cursor is at the bottom of the window, then the file must
  1821.  *           be scrolled up.   If the cursor is at the bottom of the file,
  1822.  *           then scroll line up until it is at top of screen.
  1823.  */
  1824. int  move_down( WINDOW *window )
  1825. {
  1826. int  rc;
  1827.  
  1828.    rc = prepare_move_down( window );
  1829.    sync( window );
  1830.    return( rc );
  1831. }
  1832.  
  1833.  
  1834. /*
  1835.  * Name:    prepare_move_down
  1836.  * Purpose: Do the stuff needed to move the cursor down one line.
  1837.  * Date:    June 5, 1991
  1838.  * Passed:  window:  pointer to current window
  1839.  * Notes:   Put all the stuff needed to move the cursor down one line in
  1840.  *           one function, so several functions can use the guts of the
  1841.  *           algorithm.
  1842.  */
  1843. int  prepare_move_down( WINDOW *window )
  1844. {
  1845. int  rc = OK;
  1846. register WINDOW *win;   /* put window pointer in a register */
  1847. int  at_bottom = FALSE; /* is cline at bottom of screen */
  1848.  
  1849.    win = window;
  1850.    entab_linebuff( );
  1851.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1852.       return( ERROR );
  1853.    if (win->cline == win->bottom_line) {
  1854.       win->file_info->dirty = LOCAL;
  1855.       at_bottom = TRUE;
  1856.    }
  1857.    if (!at_bottom)
  1858.       update_line( win );
  1859.    if (win->ll->len != EOF) {
  1860.       win->bin_offset += win->ll->len;
  1861.       ++win->rline;             /* ALWAYS increment line counter */
  1862.       win->ll = win->ll->next;
  1863.       if (!at_bottom) {
  1864.          ++win->cline;          /* if not at bottom of screen move down */
  1865.          show_curl_line( win );
  1866.       }
  1867.    } else if (win->cline > win->top_line + win->ruler) {
  1868.       --win->cline;
  1869.       win->file_info->dirty = LOCAL;
  1870.       rc = ERROR;
  1871.    } else
  1872.       rc = ERROR;
  1873.    return( rc );
  1874. }
  1875.  
  1876.  
  1877. /*
  1878.  * Name:    move_left
  1879.  * Purpose: To move the cursor left one character
  1880.  * Date:    June 5, 1991
  1881.  * Passed:  window:  pointer to current window
  1882.  * Notes:   If the cursor is already at the left of the screen, then
  1883.  *           scroll horizontally if we're not at beginning of line.
  1884.  */
  1885. int  move_left( WINDOW *window )
  1886. {
  1887. int  new_ruler = FALSE;
  1888.  
  1889.    if (window->ccol > window->start_col) {
  1890.       show_ruler_char( window );
  1891.       --window->ccol;
  1892.       --window->rcol;
  1893.    } else if (window->ccol == window->start_col && window->rcol > 0) {
  1894.       --window->rcol;
  1895.       --window->bcol;
  1896.       window->file_info->dirty = LOCAL;
  1897.       new_ruler = TRUE;
  1898.    }
  1899.    sync( window );
  1900.    if (new_ruler) {
  1901.       make_ruler( window );
  1902.       show_ruler( window );
  1903.    }
  1904.    return( OK );
  1905. }
  1906.  
  1907.  
  1908. /*
  1909.  * Name:    move_right
  1910.  * Purpose: To move the cursor right one character
  1911.  * Date:    June 5, 1991
  1912.  * Passed:  window:  pointer to current window
  1913.  * Notes:   If the cursor is already at the right of the screen (logical
  1914.  *          column 80) then scroll horizontally right.
  1915.  */
  1916. int  move_right( WINDOW *window )
  1917. {
  1918. int  new_ruler = FALSE;
  1919.  
  1920.    if (window->rcol < g_display.line_length - 1) {
  1921.       if (window->ccol < window->end_col) {
  1922.          show_ruler_char( window );
  1923.          ++window->ccol;
  1924.          ++window->rcol;
  1925.       } else if (window->ccol == window->end_col) {
  1926.          ++window->rcol;
  1927.          ++window->bcol;
  1928.          window->file_info->dirty = LOCAL;
  1929.          new_ruler = TRUE;
  1930.       }
  1931.    }
  1932.    sync( window );
  1933.    if (new_ruler) {
  1934.       make_ruler( window );
  1935.       show_ruler( window );
  1936.    }
  1937.    return( OK );
  1938. }
  1939.  
  1940.  
  1941. /*
  1942.  * Name:    pan_left
  1943.  * Purpose: To pan the screen left one character
  1944.  * Date:    January 5, 1992
  1945.  * Passed:  window:  pointer to current window
  1946.  */
  1947. int  pan_left( WINDOW *window )
  1948. {
  1949. /*
  1950.  * if (window->bcol == 0) {
  1951.  *    if (window->ccol > window->start_col) {
  1952.  *       show_ruler_char( window );
  1953.  *       --window->ccol;
  1954.  *       --window->rcol;
  1955.  *    }
  1956.  * } else if (window->bcol > 0 ) {
  1957.  * * *  Scroll window left function:
  1958.  * * *      --window->bcol;
  1959.  * * *      if (window->ccol < g_display.ncols - 1)
  1960.  * * *         ++window->ccol;
  1961.  * * *      else
  1962.  * * *         --window->rcol;
  1963.  */
  1964.    if (window->bcol > 0 ) {
  1965.       --window->bcol;
  1966.       --window->rcol;
  1967.       window->file_info->dirty = LOCAL;
  1968.       make_ruler( window );
  1969.       show_ruler( window );
  1970.    }
  1971.    sync( window );
  1972.    return( OK );
  1973. }
  1974.  
  1975.  
  1976. /*
  1977.  * Name:    pan_right
  1978.  * Purpose: To pan the screen right one character
  1979.  * Date:    January 5, 1992
  1980.  * Passed:  window:  pointer to current window
  1981.  */
  1982. int  pan_right( WINDOW *window )
  1983. {
  1984.    if (window->rcol < g_display.line_length - 1) {
  1985. /*
  1986.  *      scroll screen right function:
  1987.  *      if (window->ccol > 0)
  1988.  *         --window->ccol;
  1989.  *      else
  1990.  *         ++window->rcol;
  1991.  */
  1992.       ++window->rcol;
  1993.       ++window->bcol;
  1994.       window->file_info->dirty = LOCAL;
  1995.       make_ruler( window );
  1996.       show_ruler( window );
  1997.    }
  1998.    sync( window );
  1999.    return( OK );
  2000. }
  2001.  
  2002.  
  2003. /*
  2004.  * Name:    word_left
  2005.  * Purpose: To move the cursor left one word
  2006.  * Date:    June 5, 1991
  2007.  * Passed:  window:  pointer to current window
  2008.  * Notes:   Words are considered strings of letters, numbers and underscores,
  2009.  *          which must be separated by other characters.
  2010.  */
  2011. int  word_left( WINDOW *window )
  2012. {
  2013. text_ptr p;             /* text pointer */
  2014. int  len;               /* length of current line */
  2015. int  rc;
  2016. register int rcol;
  2017. long rline;
  2018. line_list_ptr ll;
  2019. WINDOW w;
  2020.  
  2021.    entab_linebuff( );
  2022.    if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  2023.       return( ERROR );
  2024.    rc = OK;
  2025.    dup_window_info( &w, window );
  2026.    rline = window->rline;
  2027.    rcol  = window->rcol;
  2028.    ll = window->ll;
  2029.    if (ll->len != EOF) {
  2030.       p = ll->line;
  2031.       len = ll->len;
  2032.       rcol = rcol >= len ? len-1 : rcol;
  2033.       if (rcol >= 0)
  2034.          p += rcol;
  2035.  
  2036.       if (p != NULL && rcol > 0 && !myiswhitespc(*p) && !myiswhitespc(*(p-1))) {
  2037.          for (; rcol >= 0 && !myiswhitespc( *p ); rcol--, p--);
  2038.          ++rcol;
  2039.          check_virtual_col( window, rcol, rcol );
  2040.          make_ruler( window );
  2041.          show_ruler( window );
  2042.       } else {
  2043.  
  2044.          /*
  2045.           * if we are on the first letter of a word, get off.
  2046.           */
  2047.          if (p != NULL)
  2048.             for (; rcol >= 0 && !myiswhitespc( *p ); rcol--, p--);
  2049.  
  2050.          /*
  2051.           * go to the next line if word begins at 1st col in line.
  2052.           */
  2053.          if (rcol < 0) {
  2054.             if (ll->prev != NULL) {
  2055.                --rline;
  2056.                ll = ll->prev;
  2057.                p = ll->line;
  2058.                rcol = ll->len - 1;
  2059.                if (rcol >= 0)
  2060.                   p += rcol;
  2061.             } else
  2062.                rc = ERROR;
  2063.          }
  2064.  
  2065.          /*
  2066.           * skip all blanks until we get to a previous word
  2067.           */
  2068.          while (rc == OK && (p == NULL || (p != NULL && myiswhitespc( *p )))) {
  2069.             for (; rcol >= 0 && myiswhitespc( *p ); rcol--, p--);
  2070.             if (rcol < 0) {
  2071.                if (ll->prev != NULL) {
  2072.                   --rline;
  2073.                   ll = ll->prev;
  2074.                   p = ll->line;
  2075.                   rcol = ll->len - 1;
  2076.                   if (rcol >= 0)
  2077.                      p += rcol;
  2078.                } else
  2079.                   rc = ERROR;
  2080.             } else
  2081.                break;
  2082.          }
  2083.  
  2084.          /*
  2085.           * now, find the beginning of the word.
  2086.           */
  2087.          if (rc == OK  &&  p != NULL) {
  2088.             for (; rcol >= 0 && !myiswhitespc( *p ); rcol--, p--);
  2089.             bin_offset_adjust( window, rline );
  2090.             find_adjust( window, ll, rline, rcol+1 );
  2091.             if (rline != w.rline && !window->file_info->dirty) {
  2092.                update_line( &w );
  2093.                show_curl_line( window );
  2094.             }
  2095.             make_ruler( window );
  2096.             show_ruler( window );
  2097.          } else
  2098.             rc = ERROR;
  2099.       }
  2100.    } else
  2101.       rc = ERROR;
  2102.  
  2103.    sync( window );
  2104.    return( rc );
  2105. }
  2106.  
  2107.  
  2108. /*
  2109.  * Name:    word_right
  2110.  * Purpose: To move the cursor right one word
  2111.  * Date:    June 5, 1991
  2112.  * Passed:  window:  pointer to current window
  2113.  * Notes:   Words are considered strings of letters, numbers and underscores,
  2114.  *           which must be separated by other characters.
  2115.  */
  2116. int  word_right( WINDOW *window )
  2117. {
  2118. int  len;               /* length of current line */
  2119. text_ptr p;             /* text pointer */
  2120. int  rc;
  2121. WINDOW w;
  2122. register int rcol;
  2123. line_list_ptr ll;
  2124. long rline;
  2125.  
  2126.    entab_linebuff( );
  2127.    if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  2128.       return( ERROR );
  2129.    rc = OK;
  2130.    dup_window_info( &w, window );
  2131.    rline = window->rline;
  2132.    rcol  = window->rcol;
  2133.    ll = window->ll;
  2134.    if (ll->len != EOF) {
  2135.       p = ll->line;
  2136.       len = ll->len;
  2137.  
  2138.       /*
  2139.        * if rcol is past EOL, move it to EOL
  2140.        */
  2141.       rcol = rcol >= len ? len-1 : rcol;
  2142.       if (rcol >= 0)
  2143.          p += rcol;
  2144.  
  2145.       /*
  2146.        * if cursor is on a word, find end of word.
  2147.        */
  2148.       if (p != NULL)
  2149.          for (; rcol < len && !myiswhitespc( *p ); rcol++, p++);
  2150.       else
  2151.          rcol = len;
  2152.  
  2153.       /*
  2154.        * go to the next line if word ends at eol.
  2155.        */
  2156.       if (rcol == len) {
  2157.          ++rline;
  2158.          ll = ll->next;
  2159.          if (ll->len != EOF) {
  2160.             p = ll->line;
  2161.             len = ll->len;
  2162.             rcol = 0;
  2163.          } else
  2164.             rc = ERROR;
  2165.       }
  2166.  
  2167.       /*
  2168.        * now, go forward thru the file looking for the first letter of word.
  2169.        */
  2170.       while (rc == OK && (p == NULL  ||  (p != NULL && myiswhitespc( *p )))) {
  2171.          for (; rcol < len && myiswhitespc( *p ); rcol++, p++);
  2172.          if (rcol == len) {
  2173.             ++rline;
  2174.             ll = ll->next;
  2175.             if (ll->len != EOF) {
  2176.                p = ll->line;
  2177.                len = ll->len;
  2178.                rcol = 0;
  2179.             } else
  2180.                rc = ERROR;
  2181.          } else
  2182.             break;
  2183.       }
  2184.    } else
  2185.       rc = ERROR;
  2186.  
  2187.    if (rc == OK) {
  2188.       bin_offset_adjust( window, rline );
  2189.       find_adjust( window, ll, rline, rcol );
  2190.       make_ruler( window );
  2191.       show_ruler( window );
  2192.    }
  2193.  
  2194.    if (rline != w.rline && !window->file_info->dirty) {
  2195.       update_line( &w );
  2196.       show_curl_line( window );
  2197.    }
  2198.    sync( window );
  2199.    return( rc );
  2200. }
  2201.  
  2202.  
  2203. /*
  2204.  * Name:    next_dirty_line
  2205.  * Purpose: To move the cursor to the next dirty line, if it exists
  2206.  * Date:    April 1, 1993
  2207.  * Passed:  window:  pointer to current window
  2208.  */
  2209. int  next_dirty_line( WINDOW *window )
  2210. {
  2211. int  rc;
  2212. line_list_ptr ll;
  2213. long rline;
  2214. long bin_offset;       /* binary offset */
  2215. WINDOW w;
  2216.  
  2217.    entab_linebuff( );
  2218.    if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  2219.       return( ERROR );
  2220.    rc = OK;
  2221.    dup_window_info( &w, window );
  2222.    rline = window->rline;
  2223.    ll = window->ll;
  2224.    bin_offset = window->bin_offset;
  2225.    if (ll->len != EOF) {
  2226.       while (rc == OK) {
  2227.          if (ll->len != EOF) {
  2228.             ++rline;
  2229.             bin_offset += ll->len;
  2230.             ll = ll->next;
  2231.             if (ll->dirty == TRUE)
  2232.                break;
  2233.          } else
  2234.             rc = ERROR;
  2235.       }
  2236.    } else
  2237.       rc = ERROR;
  2238.  
  2239.    if (rc == OK) {
  2240.       window->bin_offset = bin_offset;
  2241.       find_adjust( window, ll, rline, window->rcol );
  2242.       make_ruler( window );
  2243.       show_ruler( window );
  2244.    } else
  2245.       error( WARNING, window->bottom_line, utils16 );
  2246.  
  2247.    if (rline != w.rline && !window->file_info->dirty) {
  2248.       update_line( &w );
  2249.       show_curl_line( window );
  2250.    }
  2251.    sync( window );
  2252.    return( rc );
  2253. }
  2254.  
  2255.  
  2256. /*
  2257.  * Name:    prev_dirty_line
  2258.  * Purpose: To move the cursor to the prev dirty line, if it exists
  2259.  * Date:    April 1, 1993
  2260.  * Passed:  window:  pointer to current window
  2261.  */
  2262. int  prev_dirty_line( WINDOW *window )
  2263. {
  2264. int  rc;
  2265. line_list_ptr ll;
  2266. long rline;
  2267. long bin_offset;        /* binary offset */
  2268. WINDOW w;
  2269.  
  2270.    entab_linebuff( );
  2271.    if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  2272.       return( ERROR );
  2273.    rc = OK;
  2274.    dup_window_info( &w, window );
  2275.    rline = window->rline;
  2276.    ll = window->ll;
  2277.    bin_offset = window->bin_offset;
  2278.    if (ll->prev != NULL) {
  2279.       while (rc == OK) {
  2280.          if (ll->prev != NULL) {
  2281.             --rline;
  2282.             ll = ll->prev;
  2283.             bin_offset -= ll->len;
  2284.             if (ll->dirty == TRUE)
  2285.                break;
  2286.          } else
  2287.             rc = ERROR;
  2288.       }
  2289.    } else
  2290.       rc = ERROR;
  2291.  
  2292.    if (rc == OK) {
  2293.       window->bin_offset = bin_offset;
  2294.       find_adjust( window, ll, rline, window->rcol );
  2295.       make_ruler( window );
  2296.       show_ruler( window );
  2297.    } else
  2298.       error( WARNING, window->bottom_line, utils16 );
  2299.  
  2300.    if (rline != w.rline && !window->file_info->dirty) {
  2301.       update_line( &w );
  2302.       show_curl_line( window );
  2303.    }
  2304.    sync( window );
  2305.    return( rc );
  2306. }
  2307.  
  2308.  
  2309. /*
  2310.  * Name:    center_window
  2311.  * Purpose: To place the current line or cursor in the center of a window.
  2312.  * Date:    June 5, 1991
  2313.  * Passed:  window:  pointer to current window
  2314.  */
  2315. int  center_window( WINDOW *window )
  2316. {
  2317. int  center;
  2318. int  center_line;
  2319. int  diff;
  2320. register file_infos *file;
  2321. register WINDOW *win;           /* put window pointer in a register */
  2322.  
  2323.    win = window;
  2324.    file = win->file_info;
  2325.    center = (win->bottom_line + 1 - win->top_line) / 2 - win->ruler;
  2326.    center_line = win->top_line + win->ruler + center;
  2327.    diff = center_line - win->cline;
  2328.    entab_linebuff( );
  2329.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  2330.       return( ERROR );
  2331.    if (g_status.command == CenterWindow) {
  2332.       if (diff > 0) {
  2333.          if (win->rline + diff <= file->length) {
  2334.             update_line( win );
  2335.             win->cline += diff;
  2336.             win->rline += diff;
  2337.             for (; diff > 0; diff--) {
  2338.                win->bin_offset += win->ll->len;
  2339.                win->ll = win->ll->next;
  2340.             }
  2341.             show_curl_line( win );
  2342.          }
  2343.       } else if (diff < 0) {
  2344.          update_line( win );
  2345.          win->cline += diff;
  2346.          win->rline += diff;
  2347.          for (; diff < 0; diff++) {
  2348.             win->ll = win->ll->prev;
  2349.             win->bin_offset -= win->ll->len;
  2350.          }
  2351.          show_curl_line( win );
  2352.       }
  2353.    } else {
  2354.       if (diff > 0) {
  2355.          win->cline += diff;
  2356.          if ((long)(win->cline+1 - (win->top_line + win->ruler)) > win->rline)
  2357.             win->cline = (win->top_line + win->ruler) - 1 + (int)win->rline;
  2358.          file->dirty = LOCAL;
  2359.       } else if (diff < 0) {
  2360.          win->cline = win->cline + diff;
  2361.          file->dirty = LOCAL;
  2362.       }
  2363.    }
  2364.    if (g_status.command == CenterWindow  ||  g_status.command == CenterLine)
  2365.       sync( win );
  2366.    return( OK );
  2367. }
  2368.  
  2369.  
  2370. /*
  2371.  * Name:    horizontal_screen_right
  2372.  * Purpose: To move the cursor one screen to the right
  2373.  * Date:    September 13, 1991
  2374.  * Passed:  window:  pointer to current window
  2375.  * Notes:   Add 80 columns to the real cursor.  If the cursor is past the
  2376.  *          maximum line length then move it back.
  2377.  */
  2378. int  horizontal_screen_right( WINDOW *window )
  2379. {
  2380. int  col;
  2381.  
  2382.    col = window->rcol;
  2383.    col += (window->end_col + 1 - window->start_col);
  2384.    if (col < MAX_LINE_LENGTH) {
  2385.       window->rcol = col;
  2386.       window->bcol += (window->end_col + 1 - window->start_col);
  2387.       window->file_info->dirty = LOCAL;
  2388.       check_virtual_col( window, window->rcol, window->ccol );
  2389.       make_ruler( window );
  2390.       show_ruler( window );
  2391.    }
  2392.    sync( window );
  2393.    return( OK );
  2394. }
  2395.  
  2396.  
  2397. /*
  2398.  * Name:    horizontal_screen_left
  2399.  * Purpose: To move the cursor one screen to the left
  2400.  * Date:    September 13, 1991
  2401.  * Passed:  window:  pointer to current window
  2402.  * Notes:   Subtract screen width from the real cursor.  If the cursor is less
  2403.  *           than zero then see if bcol is zero.  If bcol is not zero then make
  2404.  *           bcol zero.
  2405.  */
  2406. int  horizontal_screen_left( WINDOW *window )
  2407. {
  2408. int  screen_width;
  2409.  
  2410.    screen_width = window->end_col + 1 - window->start_col;
  2411.    if (window->rcol - screen_width < 0) {
  2412.       if (window->bcol != 0) {
  2413.          window->bcol = 0;
  2414.          window->file_info->dirty = LOCAL;
  2415.       }
  2416.    } else {
  2417.       window->rcol -= screen_width;
  2418.       window->bcol -= screen_width;
  2419.       if (window->bcol < 0)
  2420.          window->bcol = 0;
  2421.       window->file_info->dirty = LOCAL;
  2422.    }
  2423.    check_virtual_col( window, window->rcol, window->ccol );
  2424.    sync( window );
  2425.    make_ruler( window );
  2426.    show_ruler( window );
  2427.    return( OK );
  2428. }
  2429.  
  2430.  
  2431. /*
  2432.  * Name:    goto_top_file
  2433.  * Purpose: To move the cursor to the top of the file.
  2434.  * Date:    June 5, 1991
  2435.  * Passed:  window:  pointer to current window
  2436.  */
  2437. int  goto_top_file( WINDOW *window )
  2438. {
  2439. register WINDOW *win;   /* put window pointer in a register */
  2440. long num;
  2441.  
  2442.    win = window;
  2443.    entab_linebuff( );
  2444.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  2445.       return( ERROR );
  2446.    if (win->rline != win->cline - (win->top_line+win->ruler-1)) {
  2447.       win->bin_offset = 0;
  2448.       win->rline = win->cline - (win->top_line+win->ruler-1);
  2449.       win->ll = win->file_info->line_list;
  2450.       for (num=1; num < win->rline; num++) {
  2451.          win->bin_offset += win->ll->len;
  2452.          win->ll = win->ll->next;
  2453.       }
  2454.       display_current_window( win );
  2455.    }
  2456.    sync( win );
  2457.    return( OK );
  2458. }
  2459.  
  2460.  
  2461. /*
  2462.  * Name:    goto_end_file
  2463.  * Purpose: To move the cursor to the end of the file.
  2464.  * Date:    June 5, 1991
  2465.  * Passed:  window:  pointer to current window
  2466.  */
  2467. int  goto_end_file( WINDOW *window )
  2468. {
  2469. register WINDOW *win;  /* put window pointer in a register */
  2470. line_list_ptr ll;
  2471. long length;
  2472.  
  2473.    win = window;
  2474.    entab_linebuff( );
  2475.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  2476.       return( ERROR );
  2477.    length = win->file_info->length;
  2478.    if (length > win->rline + win->bottom_line - win->cline) {
  2479.       win->rline = length - (win->bottom_line - win->cline) + 1;
  2480.       win->ll = win->file_info->line_list_end;
  2481.       for (;length >= win->rline; length--)
  2482.          win->ll = win->ll->prev;
  2483.  
  2484.       win->bin_offset = 0;
  2485.       ll = win->file_info->line_list;
  2486.       for (length = 1; length < win->rline; length++) {
  2487.          win->bin_offset += ll->len;
  2488.          ll = ll->next;
  2489.       }
  2490.  
  2491.       display_current_window( win );
  2492.    }
  2493.    sync( win );
  2494.    return( OK );
  2495. }
  2496.  
  2497.  
  2498. /*
  2499.  * Name:    goto_line
  2500.  * Purpose: To move the cursor to a particular line in the file
  2501.  * Date:    June 5, 1991
  2502.  * Passed:  window:  pointer to current window
  2503.  */
  2504. int  goto_line( WINDOW *window )
  2505. {
  2506. long number;            /* line number selected */
  2507. long n;
  2508. char num_str[MAX_COLS]; /* line number as string */
  2509. register WINDOW *win;   /* put window pointer in a register */
  2510. line_list_ptr ll;
  2511. int  rc;
  2512.  
  2513.    win = window;
  2514.    entab_linebuff( );
  2515.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  2516.       return( ERROR );
  2517.    /*
  2518.     * find out where we are going
  2519.     */
  2520.    num_str[0] = '\0';
  2521.    /*
  2522.     * line number:
  2523.     */
  2524.    if (get_name( find11, win->bottom_line, num_str,
  2525.                  g_display.message_color ) != OK  ||  *num_str == '\0')
  2526.       return( ERROR );
  2527.    number = atol( num_str );
  2528.  
  2529.    if (number > 0  && number <= (long)win->file_info->length) {
  2530.       update_line( win );
  2531.       ll = win->ll;
  2532.       n = win->rline;
  2533.       if (number < win->rline) {
  2534.          if (n - number < number - 1) {
  2535.             for (; n > number; n--) {
  2536.                ll = ll->prev;
  2537.                win->bin_offset -= ll->len;
  2538.             }
  2539.          } else {
  2540.             ll = win->file_info->line_list;
  2541.             n = 1;
  2542.             for (; n < number; n++) {
  2543.                win->bin_offset += ll->len;
  2544.                ll = ll->next;
  2545.             }
  2546.          }
  2547.       } else if (number > win->rline) {
  2548.          for (; n < number; n++) {
  2549.             win->bin_offset += ll->len;
  2550.             ll = ll->next;
  2551.          }
  2552.       }
  2553.       find_adjust( win, ll, number, win->rcol );
  2554.       if (!win->file_info->dirty)
  2555.          show_curl_line( win );
  2556.       rc = OK;
  2557.    } else {
  2558.       /*
  2559.        * out of range.  must be in the range 1 -
  2560.        */
  2561.       strcat( num_str, find12 );
  2562.       ltoa( win->file_info->length, num_str+25, 10 );
  2563.       error( WARNING, win->bottom_line, num_str );
  2564.       rc = ERROR;
  2565.    }
  2566.    return( rc );
  2567. }
  2568.  
  2569.  
  2570. /*
  2571.  * Name:    set_marker
  2572.  * Purpose: To set file marker
  2573.  * Date:    December 28, 1991
  2574.  * Passed:  window:  pointer to current window
  2575.  */
  2576. int  set_marker( WINDOW *window )
  2577. {
  2578. register MARKER  *marker;       /* put the marker in a register */
  2579.  
  2580.    marker = &window->file_info->marker[g_status.command - SetMark1];
  2581.    marker->rline  = window->rline;
  2582.    marker->rcol   = window->rcol;
  2583.    marker->ccol   = window->ccol;
  2584.    marker->bcol   = window->bcol;
  2585.    marker->marked = TRUE;
  2586.    return( OK );
  2587. }
  2588.  
  2589.  
  2590. /*
  2591.  * Name:    goto_marker
  2592.  * Purpose: To goto a file marker
  2593.  * Date:    December 28, 1991
  2594.  * Passed:  window:  pointer to current window
  2595.  */
  2596. int  goto_marker( WINDOW *window )
  2597. {
  2598. int  m;
  2599. file_infos *file;
  2600. long new_rline;
  2601. long n;
  2602. MARKER *marker;
  2603. register WINDOW *win;   /* put window pointer in a register */
  2604. line_list_ptr ll;
  2605. int  rc;
  2606.  
  2607.    win = window;
  2608.    m = g_status.command - GotoMark1;
  2609.    file = win->file_info;
  2610.    marker = &file->marker[m];
  2611.    if (marker->marked) {
  2612.       entab_linebuff( );
  2613.       if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  2614.          return( ERROR );
  2615.       file->dirty = LOCAL;
  2616.       if (marker->rline > file->length)
  2617.          marker->rline = file->length;
  2618.       if (marker->rline < 1l)
  2619.          marker->rline = 1l;
  2620.       new_rline = marker->rline;
  2621.       ll = win->ll;
  2622.       if (new_rline < win->rline) {
  2623.          if (win->rline - new_rline < new_rline - 1) {
  2624.             for (n=win->rline; n > new_rline; n--) {
  2625.                ll = ll->prev;
  2626.                win->bin_offset -= ll->len;
  2627.             }
  2628.          } else {
  2629.             ll = win->file_info->line_list;
  2630.             win->bin_offset = 0;
  2631.             n = 1;
  2632.             for (; n < new_rline; n++) {
  2633.                win->bin_offset += ll->len;
  2634.                ll = ll->next;
  2635.             }
  2636.          }
  2637.       } else if (new_rline > win->rline) {
  2638.          n = win->rline;
  2639.          for (; n < new_rline; n++) {
  2640.             win->bin_offset += ll->len;
  2641.             ll = ll->next;
  2642.          }
  2643.       }
  2644.       win->rline  = new_rline;
  2645.       win->ll     = ll;
  2646.       win->rcol   = marker->rcol;
  2647.       win->ccol   = marker->ccol;
  2648.       win->bcol   = marker->bcol;
  2649.       if (win->rline < (win->cline - ((win->top_line + win->ruler) - 1)))
  2650.          win->cline = (int)win->rline + (win->top_line + win->ruler) - 1;
  2651.       check_virtual_col( win, win->rcol, win->ccol );
  2652.       make_ruler( window );
  2653.       show_ruler( window );
  2654.       rc = OK;
  2655.    } else {
  2656.       if (m == 9)
  2657.          m = -1;
  2658.       *(utils13 + 7) = (char)('0' + m + 1);
  2659.       /*
  2660.        * marker not set
  2661.        */
  2662.       error( WARNING, win->bottom_line, utils13 );
  2663.       rc = ERROR;
  2664.    }
  2665.    return( rc );
  2666. }
  2667.  
  2668.  
  2669. /*
  2670.  * Name:    date_time_stamp
  2671.  * Purpose: put system date and time into file at cursor position
  2672.  * Date:    June 5, 1992
  2673.  * Passed:  window:  pointer to current window
  2674.  */
  2675. int  date_time_stamp( WINDOW *window )
  2676. {
  2677. char date_time[MAX_COLS];
  2678. char stuff[20];
  2679. register char *dt;
  2680. int  year, month, day;
  2681. int  hours, minutes;
  2682. int  one, two, three;
  2683. int  i;
  2684. int  pm;
  2685.  
  2686.  
  2687.    get_date( &year, &month, &day, &i );
  2688.    get_time( &hours, &minutes, &i, &i );
  2689.    dt = date_time;
  2690.  
  2691.    /*
  2692.     * mod year with 100 if needed.
  2693.     */
  2694.    switch (mode.date_style) {
  2695.       case MM_DD_YY  :
  2696.       case DD_MM_YY  :
  2697.       case YY_MM_DD  :
  2698.          year = year % 100;
  2699.    }
  2700.  
  2701.    switch (mode.date_style) {
  2702.       case DD_MM_YY   :
  2703.       case DD_MM_YYYY :
  2704.          one = day;
  2705.          two = month;
  2706.          three = year;
  2707.          break;
  2708.       case YY_MM_DD   :
  2709.       case YYYY_MM_DD :
  2710.          one = year;
  2711.          two = month;
  2712.          three = day;
  2713.          break;
  2714.       case MM_DD_YY   :
  2715.       case MM_DD_YYYY :
  2716.       default         :
  2717.          one = month;
  2718.          two = day;
  2719.          three = year;
  2720.          break;
  2721.    }
  2722.    strcpy( dt, itoa( one, stuff, 10 ) );
  2723.    strcat( dt, "-" );
  2724.    strcat( dt, itoa( two, stuff, 10 ) );
  2725.    strcat( dt, "-" );
  2726.    strcat( dt, itoa( three, stuff, 10 ) );
  2727.  
  2728.    strcat( dt, "  " );
  2729.  
  2730.    pm = FALSE;
  2731.    if (mode.time_style == _12_HOUR) {
  2732.       if (hours >= 12 && hours < 24)
  2733.          pm = TRUE;
  2734.       if (hours < 1)
  2735.          hours = 12;
  2736.       else if (hours >= 13)
  2737.          hours -= 12;
  2738.    }
  2739.  
  2740.    if (hours < 1)
  2741.       strcat( dt, "0" );
  2742.    strcat( dt, itoa( hours, stuff, 10 ) );
  2743.    strcat( dt, ":" );
  2744.    if (minutes < 10)
  2745.       strcat( dt, "0" );
  2746.    strcat( dt, itoa( minutes, stuff, 10 ) );
  2747.    if (mode.time_style == _12_HOUR)
  2748.       strcat( dt, pm == FALSE ? "am" : "pm" );
  2749.    strcat( dt, "  " );
  2750.    return( add_chars( dt, window ) );
  2751. }
  2752.  
  2753.  
  2754. /*
  2755.  * Name:    add_chars
  2756.  * Purpose: insert string into file
  2757.  * Date:    June 5, 1992
  2758.  * Passed:  string:  string to add to file
  2759.  *          window:  pointer to current window
  2760.  */
  2761. int  add_chars( char *string, WINDOW *window )
  2762. {
  2763. int  rc = OK;
  2764.  
  2765.    while (*string) {
  2766.       g_status.key_pressed = *string;
  2767.       rc = insert_overwrite( window );
  2768.       ++string;
  2769.    }
  2770.    return( rc );
  2771. }
  2772.